package org.csu.mypetstore.api.ws;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.csu.mypetstore.api.config.WebSocketConfig;
import org.csu.mypetstore.api.config.WebSocketMessageVODecoder;
import org.csu.mypetstore.api.config.WebSocketMessageVOEncoding;
import org.csu.mypetstore.api.entity.ChatUser;
import org.csu.mypetstore.api.entity.ContactData;
import org.csu.mypetstore.api.entity.Group;
import org.csu.mypetstore.api.persistence.ContactDataMapper;
import org.csu.mypetstore.api.persistence.GroupMapper;
import org.csu.mypetstore.api.vo.AccountVO;
import org.csu.mypetstore.api.vo.ChatUserVO;
import org.csu.mypetstore.api.vo.ContactDataVO;
import org.csu.mypetstore.api.vo.MessageVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpSession;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

@ServerEndpoint(value = "/api/chat", decoders = WebSocketMessageVODecoder.class,encoders = WebSocketMessageVOEncoding.class, configurator = GetHttpSessionConfigurator.class)
@Component
public class ChatEndpoint implements ApplicationContextAware {

    //用来存储每一个客户端对象的ChatEndPoint对象
    private static Map<ChatUserVO,ChatEndpoint> onlineUsers = new ConcurrentHashMap<>();

    //声明Session对象，通过该对象可以把消息发送给指定的用户
    private Session session;

    //声明一个HttpSession对象，我们之前再HttpSession对象中存储了用户信息
    private HttpSession httpSession;

    private static ApplicationContext applicationContext;
    //群聊：
//    @Autowired
    private GroupMapper groupMapper;
    //联系人：
//    @Autowired
    private ContactDataMapper contactDataMapper;
    //开始解决注入问题：
    public void setApplicationContext(ApplicationContext applicationContext){
        ChatEndpoint.applicationContext = applicationContext;
//        applicationContext.getBean(GroupMapper.class);
//        applicationContext.getBean(ContactDataMapper.class);
    }

    @OnOpen
    public void onOpen(Session session, EndpointConfig endpointConfig){
        this.groupMapper = applicationContext.getBean(GroupMapper.class);
        this.contactDataMapper = applicationContext.getBean(ContactDataMapper.class);
        //建立连接时调用
        //将局部的session赋值给session
        this.session = session;
        //获取HttpSession对象
        HttpSession httpSession = (HttpSession) endpointConfig.getUserProperties().get(HttpSession.class.getName());
        this.httpSession = httpSession;

        //从httpSession中获取登录用户，并存储到容器中
        AccountVO accountVO = (AccountVO) httpSession.getAttribute("login_account");
        ChatUserVO chatUser = accountVO.toChatUserVO();
        onlineUsers.put(chatUser, this);

        //新用户上线，向其他所有用户广播该用户的消息
        newUserEnter(chatUser);

        //新用户上线，向该用户发送所有除自己外已经上线的用户
        otherUsers(chatUser);
    }


    @OnMessage
    public void onMessage(MessageVO message, Session session){
        //接收到消息时调用
        Group group = groupMapper.selectById(message.getToContactId());
        System.out.println(" 信息："+message.getToContactId());
        if(group == null){//此时是私聊消息
            sendMessageToOne(message, message.getToContactId());
        }
        else{//此时是群发消息，将消息广播给群内的所有用户（消息发送者除外）
//            sendMessageTOGroup(message, message.getFromUser())
            sendMessageToPeopleInGroup(message);
        }

        //判断消息类型
//        if(message.getToContactId().equals("group")){
//            //是群发消息，将该消息转发给所有用户
//            sendMessageTOGroup(message, message.getFromUser());
//        }else{
//            //是私法消息，将消息转发给指定的用户
//            sendMessageToOne(message, message.getToContactId());
//        }
    }

    @OnClose
    public void onClose(Session session){
        //链接关闭时调用
        AccountVO accountVO=(AccountVO) httpSession.getAttribute("login_account");
        ChatUserVO chatUserVO= accountVO.toChatUserVO();

        onlineUsers.remove(chatUserVO);             //将该用户从在线用户中删除
//        offLine(chatUserVO);

    }

    //获取当前所有在线用户
    private Set<ChatUserVO> getOnlineUsers(){
        return onlineUsers.keySet();
    }

    //向其他所有用户通知有新的用户登录
    public void newUserEnter(ChatUserVO chatUserVO){
        ContactDataVO contactDataVO = chatUserVO.toContactDataVO();
        List<ContactDataVO> contactDataVOList = new ArrayList<>();
        contactDataVOList.add(contactDataVO);
        MessageVO messageVO = broadCastMessage(contactDataVOList);
        sendMessageTOGroup(messageVO, chatUserVO);
    }

    //向某个用户发送其他在线用户的信息
    public void otherUsers(ChatUserVO chatUserVO){
        ChatEndpoint chatEndpoint = onlineUsers.get(chatUserVO);

        List<ContactDataVO> contactDataVOList = new ArrayList<>();
        Set<ChatUserVO> chatUsers = onlineUsers.keySet();
        for (ChatUserVO chatUser : chatUsers){
            //如果是其他用户，就添加进列表
            if(!chatUser.getId().equals(chatUserVO.getId())){
                contactDataVOList.add(chatUser.toContactDataVO());
            }
        }
        try {
            chatEndpoint.session.getBasicRemote().sendObject(broadCastMessage(contactDataVOList));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //向所有在线用户广播某用户已下线：
    public void offLine(ChatUserVO chatUserVO){
        ContactDataVO contactDataVO = chatUserVO.toContactDataVO();
        MessageVO messageVO = broadCastMessage(contactDataVO);
        messageVO.setType("offLine");
        Set<ChatUserVO> chatUsers = onlineUsers.keySet();
        for(ChatUserVO chatUser : chatUsers){
            ChatEndpoint chatEndpoint = onlineUsers.get(chatUser);
            try {
                chatEndpoint.session.getBasicRemote().sendObject(messageVO);
            } catch (IOException e) {
                e.printStackTrace();
            } catch (EncodeException e) {
                e.printStackTrace();
            }
        }
    }

    //创建一个广播消息（广播消息的发送者和接收者均为null）
    public MessageVO broadCastMessage(Object obj){
        MessageVO messageVO = new MessageVO();
        messageVO.setId("");
        messageVO.setStatus("");
        messageVO.setType("object");
        messageVO.setSendTime(new Date());
        messageVO.setContent(obj);
        //这表示该消息是发送给所有用户的
        messageVO.setToContactId(null);
        messageVO.setFromUser(null);

        return messageVO;
    }

    //向其他所有用户发送一条消息
    public void sendMessageTOGroup(MessageVO messageVO, ChatUserVO sender){
        try {
            Set<ChatUserVO> chatUsers = onlineUsers.keySet();
            for (ChatUserVO chatUser : chatUsers){
                //如果是其他用户，就发送消息
                if(!chatUser.getId().equals(sender.getId())){
                    ChatEndpoint chatEndpoint = onlineUsers.get(chatUser);
                    chatEndpoint.session.getBasicRemote().sendObject(messageVO);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //向某个用户发送消息
    public void sendMessageToOne(MessageVO messageVO, String toContactId){
        try {
            Set<ChatUserVO> chatUsers = onlineUsers.keySet();
            for (ChatUserVO chatUser : chatUsers){
                //如果是接收用户，就发送消息(注意私聊要对消息做一定变化)
                if(chatUser.getId().equals(toContactId)){
                    messageVO.setToContactId(messageVO.getFromUser().getId());
                    ChatEndpoint chatEndpoint = onlineUsers.get(chatUser);
                    chatEndpoint.session.getBasicRemote().sendObject(messageVO);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void sendMessageToPeopleInGroup(MessageVO messageVO){
        //首先获取所有的用户
        Set<ChatUserVO> chatUserVOS = onlineUsers.keySet();
        //其次查询所有加入该群的成员
        QueryWrapper<ContactData> contactDataQueryWrapper = new QueryWrapper<>();
        contactDataQueryWrapper.eq("friendId",messageVO.getToContactId());
        List<ContactData> contactDataVOList = this.contactDataMapper.selectList(contactDataQueryWrapper);
        for(ContactData contactData : contactDataVOList){
            //向所有群内的非消息发送者推送该消息
            if(!contactData.getUserId().equals(messageVO.getFromUser().getId())){
                for(ChatUserVO chatUserVO : chatUserVOS){
                    if(chatUserVO.getId().equals(contactData.getUserId())){
                        ChatEndpoint chatEndpoint = onlineUsers.get(chatUserVO);
                        try {
                            chatEndpoint.session.getBasicRemote().sendObject(messageVO);
                        } catch (IOException e) {
                            e.printStackTrace();
                        } catch (EncodeException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }

}
